/*
 * MapFactory.cpp
 *
 *  Created on: 31/10/2009
 *      Author: marcos
 */

#include "MapFactory.h"
#include "util/exceptions/Exception.h"

// Creator es una clase auxiliar (VER MAS ABAJO: MapFactory)
// =========================================================
class Creator {
public:
	Creator(){
		this->factory = new MapElementFactory();
	};
	virtual ~Creator(){
		delete this->factory;
	};
	/*
	 * Crea el objeto del mapa y lo agrega al mismo, en caso de error devuelve una Exception.
	 */
	virtual void create(Map* map, parser::ParsedData* data) throw (util::Exception) = 0;
protected:
	MapElementFactory* factory;
};
class RoadCreator: public Creator{
	void create (Map* map, parser::ParsedData* data) throw (util::Exception) {
		this->factory->createRoad(map, data);
	}
};
class LocationCreator: public Creator{
	void create (Map* map, parser::ParsedData* data) throw (util::Exception) {
		this->factory->createLocation(map, data);
	}
};
class IntersectionCreator: public Creator{
	void create (Map* map, parser::ParsedData* data) throw (util::Exception) 	{
		this->factory->createIntersection(map, data);
	}
};

// =========================================================
util::Logger* logger() {
	return util::LoggerManager::getInstance()->getLogger();
}

// loguea los warnings que suceden al parsear
void logWarnings(parser::Parser &parser, parser::ParsedData* data) {
	while (data->hasWarnings()) {
		logger()->warn(parser.getFileName() + ":" + parser.getStrLineNumber()
				+ ": " + data->getNextWarning());
	}
}

void loadDataFromFile(Map* map, parser::Parser &parser, Creator &creator){
	while (!parser.noMoreDataInFile()) {
		parser::ParsedData* data = NULL;
		try {
			data = parser.processNextLine();
			logWarnings(parser, data);
			creator.create(map, data);
			logger()->info(data->toString());
			delete data;
		} catch (util::Exception &e) {
			// Por ahora tratamos a todas las excepciones igual.
			logger()->error(parser.getFileName() + ":" + parser.getStrLineNumber()
					+ ": " + e.getMessage());
		}
	}
}

// =========================================================

MapFactory::MapFactory() {};

MapFactory::~MapFactory() {};

Map* MapFactory::createMap(std::string mapDataPath){
	Map* map = new Map();

	// carga y agrega las intersecciones al mapa
	IntersectionCreator intersectionCreator;
	parser::IntersectionRule intersectionRule(';');
	parser::Parser intersectionParser(&intersectionRule, mapDataPath + "/Vertices.txt");
	loadDataFromFile(map, intersectionParser, intersectionCreator);

	// carga y agrega los caminos al mapa
	RoadCreator roadCreator;
	parser::RoadRule roadRule(';');
	parser::Parser roadParser(&roadRule, mapDataPath + "/Aristas.txt");
	loadDataFromFile(map, roadParser, roadCreator);

	// carga y agrega los objetos de mapa al mapa
	LocationCreator locationCreator;
	parser::MapLocationRule locationRule(';');
	parser::Parser locationParser(&locationRule, mapDataPath + "/ObjetosDeMapa.txt");
	loadDataFromFile(map, locationParser, locationCreator);

	return map;
};
